#include "barcode_scan.h"
#include <QDebug>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>

BarcodeScan::BarcodeScan(QObject *parent) : QThread(parent)
{

}

BarcodeScan::~BarcodeScan()
{
    ttyEnd();
}

bool BarcodeScan::init()
{
    return ttyInit();
}

void BarcodeScan::run()
{
    QString* barcode = NULL;

    while (true) {
        barcode = readBarcode();
        // sendSignal(barcode);
        emit barcodeScanned((const QString*)barcode);
    }
}

QString BarcodeScan::getErrorMsg()
{
    return this->errorMsg;
}

QString* BarcodeScan::readBarcode()
{
    ttyFlush();
    size_t readSize = ttyRead(barcodeBuf, MAX_BUF_SZ);
    ttyFlush();

    if (readSize <= 0) {
        qCritical() << "Read barcode failed!\n";
        return NULL;
    }

    return new QString(barcodeBuf);
}

bool BarcodeScan::ttyInit()
{

    qDebug() << "Begin init tty" << endl;
    serialFd = open(COM2, O_RDWR);
    qDebug() << "Begin open COM2" << endl;

    if (serialFd < 0) {
        this->errorMsg = QString("设备 %1 打开失败").arg(COM2);
        qCritical("Open %s failed.\n", COM2);
        return false;
    }
    qDebug() << "Open COM2 successfully." << endl;

    // 保存标准输入和串口的初始termio
    tcgetattr(BarcodeScan::serialFd, &oldSerialTermio);
    bzero(&serialTermio, sizeof(termios));

    serialTermio.c_cflag = BAUD_RATE | CS8;
    serialTermio.c_iflag = IGNPAR | ICRNL;
    serialTermio.c_oflag = 0;
    serialTermio.c_lflag = ICANON;

    serialTermio.c_cc[VINTR]    = 0;   // Ctrl-c
    serialTermio.c_cc[VQUIT]    = 0;   // 'Ctrl-\'
    serialTermio.c_cc[VERASE]   = 0;   // del
    serialTermio.c_cc[VKILL]    = 0;   // @
    serialTermio.c_cc[VEOF]     = 4;   // Ctrl-d
    serialTermio.c_cc[VTIME]    = 0;   // 不使用分割字元组的计时器
    serialTermio.c_cc[VMIN]     = 1;   // 在读取到 1 个字元前先停止
    serialTermio.c_cc[VSWTC]    = 0;   // '\0'
    serialTermio.c_cc[VSTART]   = 0;   // Ctrl-q
    serialTermio.c_cc[VSTOP]    = 0;   // Ctrl-s
    serialTermio.c_cc[VSUSP]    = 0;   // Ctrl-z
    serialTermio.c_cc[VEOL]     = 0;   // '\0'
    serialTermio.c_cc[VREPRINT] = 0;   // Ctrl-r
    serialTermio.c_cc[VDISCARD] = 0;   // Ctrl-u
    serialTermio.c_cc[VWERASE]  = 0;   // Ctrl-w
    serialTermio.c_cc[VLNEXT]   = 0;   // Ctrl-v
    serialTermio.c_cc[VEOL2]    = 0;   // '\0'

    tcflush(serialFd, TCIFLUSH);
    tcsetattr(serialFd, TCSANOW, &serialTermio);

    return true;
}

void BarcodeScan::ttyEnd()
{
    tcsetattr(serialFd, TCSANOW, &oldSerialTermio);
    close(serialFd);
}

ssize_t BarcodeScan::ttyRead(char* buf, size_t bufSize)
{
    memset(buf, 0, bufSize);
    int readSize = read(serialFd, buf, bufSize);
    buf[strlen(buf) - 1] = '\0';
    return readSize;
}

int BarcodeScan::ttyWrite(const char* buf, size_t bufSize)
{
    for (size_t i = 0; i < bufSize; ++i) {
        write(serialFd, &buf[i], 1);
        usleep(1000);
    }

    return tcdrain(serialFd);
}

int BarcodeScan::ttyWriteCmd(const char* buf, size_t bufSize)
{
    for (size_t i = 0; i < bufSize; ++i) {
        write(serialFd, &buf[i], 1);
        usleep(100);
    }

    usleep(300000);
    return tcdrain(serialFd);
}

void BarcodeScan::ttyFlush()
{
    tcflush(serialFd, TCIFLUSH); // 刷新输入缓冲
}

void BarcodeScan::quitThread()
{
    this->quit();
}
